
#pragma once


#include <Arduino.h>
// #include <Wire.h>
#include <SPI.h>
#include <stdlib.h>

// ioxx
#include <pin/avr_arduino.hpp>

// mega128_specific
#include <mega128_specific.hpp>

namespace m128 = mega128_specific;

// scheduler_basic
#include <scheduler_basic.hpp>
#include <scheduler_tick.hpp>

using TimeSource = scheduler_basic::ArduinoMsSource;
using TimeType = typename TimeSource::TimeType;
using TimeCycle = scheduler_basic::TimeCycle<TimeSource>;

constexpr uint8_t MAX_TASK_COUNT = 10;

using Scheduler = scheduler_basic::DelayCallback3<TimeSource, MAX_TASK_COUNT>;

// oled_basic_v2
// #include "oled_backend.hpp"
// #include "oled_basic_font.hpp"
// #include "oled_basic_v2.hpp"
// #include "oled_ssd13xx.hpp"

// namespace ob = oled_basic;

// U8g2
#include <u8g2lib.h>

// using U8Type = U8G2_SSD1306_128X64_NONAME_F_HW_I2C;
using U8Type = U8G2_SSD1309_128X64_NONAME0_F_4W_HW_SPI;

// modpash
#include "adu/basic_client.hpp"
#include "rtu/non_block_serial.hpp"

/////////////////////// PIN MAPPING /////////////////////////

constexpr auto LED_PIN_NUM = m128::LED_PIN;

constexpr auto RS485_DE_RE_PIN_NUM = 25;  // 485 收发器的DE/RE# 引脚

constexpr auto OLED_CS_PIN_NUM = 13;  // OLED 的 CS 引脚
constexpr auto OLED_DC_PIN_NUM = 12;  // OLED 的 DC 引脚

constexpr auto FONT_ROM_CS_PIN_NUM = 14;  // 字库芯片的CS 引脚

constexpr auto BUTTON_LEFT_PIN_NUM = 40;
constexpr auto BUTTON_RIGHT_PIN_NUM = 41;
constexpr auto BUTTON_UP_PIN_NUM = 42;
constexpr auto BUTTON_DOWN_PIN_NUM = 43;
constexpr auto BUTTON_OK_PIN_NUM = 44;

/////////////////////// MODBUS /////////////////////////

constexpr TimeType MODBUS_RESPONSE_TIMEOUT = 2000;  // 设置响应超时时间为2000毫秒


/////////////////////// GLOBAL GLOBALS /////////////////////////

extern Scheduler dcb;

extern U8Type u8g2;

/////////////////////// INLINE TOOLS /////////////////////////

/**
 * @brief 一边延时，一边继续执行延时任务
 *
 * 不可在延时任务内使用。主要用在主循环里简化延时控制逻辑，不必为了不阻塞延时任务而在主循环里也采用非阻塞状态机。
 *
 * @param t
 */
inline void delay_loop(TimeType t) {
    TimeCycle tc;
    
    while (!tc.delay(t)) {
        dcb.tick();
    }
}

/**
 * @brief 一边等待条件变为false，一边继续执行延时任务
 *
 * 用法：while(wait_if(should_wait == true));
 *
 * @param condition
 * @return true
 * @return false
 */
inline bool wait_if(bool condition) {
    dcb.tick();
    return condition;
}